{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "DweYe9FcbMK_"
   },
   "source": [
    "##### Copyright 2019 The TensorFlow Authors.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "cellView": "form",
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:12.996675Z",
     "iopub.status.busy": "2023-11-07T23:47:12.996423Z",
     "iopub.status.idle": "2023-11-07T23:47:13.000668Z",
     "shell.execute_reply": "2023-11-07T23:47:13.000059Z"
    },
    "id": "AVV2e0XKbJeX"
   },
   "outputs": [],
   "source": [
    "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "sUtoed20cRJJ"
   },
   "source": [
    "# 用 tf.data 加载 CSV 数据"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "C-3Xbt0FfGfs"
   },
   "source": [
    "本教程提供了如何在 TensorFlow 中使用 CSV 数据的示例。\n",
    "\n",
    "其中包括两个主要部分：\n",
    "\n",
    "1. **Loading the data off disk**\n",
    "2. **Pre-processing it into a form suitable for training.**\n",
    "\n",
    "本教程侧重于加载，并提供了一些关于预处理的快速示例。要了解有关预处理方面的更多信息，请查看[使用预处理层](https://tensorflow.google.cn/guide/keras/preprocessing_layers)指南和[使用 Keras 预处理层对结构化数据进行分类](../structured_data/preprocessing_layers.ipynb)教程。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "fgZ9gjmPfSnK"
   },
   "source": [
    "## 设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:13.004907Z",
     "iopub.status.busy": "2023-11-07T23:47:13.004295Z",
     "iopub.status.idle": "2023-11-07T23:47:15.613213Z",
     "shell.execute_reply": "2023-11-07T23:47:15.612330Z"
    },
    "id": "baYFZMW_bJHh"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2023-11-07 23:47:13.690444: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:9261] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
      "2023-11-07 23:47:13.690500: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:607] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
      "2023-11-07 23:47:13.692293: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1515] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "# Make numpy values easier to read.\n",
    "np.set_printoptions(precision=3, suppress=True)\n",
    "\n",
    "import tensorflow as tf\n",
    "from tensorflow.keras import layers"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "1ZhJYbJxHNGJ"
   },
   "source": [
    "## 内存数据"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ny5TEgcmHjVx"
   },
   "source": [
    "对于任何较小的 CSV 数据集，在其上训练 TensorFlow 模型的最简单方式是将其作为 Pandas Dataframe 或 NumPy 数组加载到内存中。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "LgpBOuU8PGFf"
   },
   "source": [
    "一个相对简单的示例是 [Abalone Dataset](https://archive.ics.uci.edu/ml/datasets/abalone)。\n",
    "\n",
    "- 数据集很小。\n",
    "- 所有输入特征都是有限范围的浮点值。\n",
    "\n",
    "以下是将数据下载到 [Pandas `DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html) 的方式："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:15.618052Z",
     "iopub.status.busy": "2023-11-07T23:47:15.617599Z",
     "iopub.status.idle": "2023-11-07T23:47:15.736323Z",
     "shell.execute_reply": "2023-11-07T23:47:15.735548Z"
    },
    "id": "IZVExo9DKoNz"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Length</th>\n",
       "      <th>Diameter</th>\n",
       "      <th>Height</th>\n",
       "      <th>Whole weight</th>\n",
       "      <th>Shucked weight</th>\n",
       "      <th>Viscera weight</th>\n",
       "      <th>Shell weight</th>\n",
       "      <th>Age</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.435</td>\n",
       "      <td>0.335</td>\n",
       "      <td>0.110</td>\n",
       "      <td>0.334</td>\n",
       "      <td>0.1355</td>\n",
       "      <td>0.0775</td>\n",
       "      <td>0.0965</td>\n",
       "      <td>7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.585</td>\n",
       "      <td>0.450</td>\n",
       "      <td>0.125</td>\n",
       "      <td>0.874</td>\n",
       "      <td>0.3545</td>\n",
       "      <td>0.2075</td>\n",
       "      <td>0.2250</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.655</td>\n",
       "      <td>0.510</td>\n",
       "      <td>0.160</td>\n",
       "      <td>1.092</td>\n",
       "      <td>0.3960</td>\n",
       "      <td>0.2825</td>\n",
       "      <td>0.3700</td>\n",
       "      <td>14</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.545</td>\n",
       "      <td>0.425</td>\n",
       "      <td>0.125</td>\n",
       "      <td>0.768</td>\n",
       "      <td>0.2940</td>\n",
       "      <td>0.1495</td>\n",
       "      <td>0.2600</td>\n",
       "      <td>16</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.545</td>\n",
       "      <td>0.420</td>\n",
       "      <td>0.130</td>\n",
       "      <td>0.879</td>\n",
       "      <td>0.3740</td>\n",
       "      <td>0.1695</td>\n",
       "      <td>0.2300</td>\n",
       "      <td>13</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   Length  Diameter  Height  Whole weight  Shucked weight  Viscera weight  \\\n",
       "0   0.435     0.335   0.110         0.334          0.1355          0.0775   \n",
       "1   0.585     0.450   0.125         0.874          0.3545          0.2075   \n",
       "2   0.655     0.510   0.160         1.092          0.3960          0.2825   \n",
       "3   0.545     0.425   0.125         0.768          0.2940          0.1495   \n",
       "4   0.545     0.420   0.130         0.879          0.3740          0.1695   \n",
       "\n",
       "   Shell weight  Age  \n",
       "0        0.0965    7  \n",
       "1        0.2250    6  \n",
       "2        0.3700   14  \n",
       "3        0.2600   16  \n",
       "4        0.2300   13  "
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "abalone_train = pd.read_csv(\n",
    "    \"https://storage.googleapis.com/download.tensorflow.org/data/abalone_train.csv\",\n",
    "    names=[\"Length\", \"Diameter\", \"Height\", \"Whole weight\", \"Shucked weight\",\n",
    "           \"Viscera weight\", \"Shell weight\", \"Age\"])\n",
    "\n",
    "abalone_train.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "hP22mdyPQ1_t"
   },
   "source": [
    "该数据集包含一组[鲍鱼](https://en.wikipedia.org/wiki/Abalone)（一种海螺）的测量值。\n",
    "\n",
    "![an abalone shell](https://tensorflow.org/images/abalone_shell.jpg)\n",
    "\n",
    "[“鲍鱼壳”](https://www.flickr.com/photos/thenickster/16641048623/)（作者：[Nicki Dugan Pogue](https://www.flickr.com/photos/thenickster/)，CC BY-SA 2.0）\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vlfGrk_9N-wf"
   },
   "source": [
    "此数据集的名义任务是根据其他测量值预测年龄，因此要把特征和标签分开以进行训练：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:15.740480Z",
     "iopub.status.busy": "2023-11-07T23:47:15.740131Z",
     "iopub.status.idle": "2023-11-07T23:47:15.745382Z",
     "shell.execute_reply": "2023-11-07T23:47:15.744661Z"
    },
    "id": "udOnDJOxNi7p"
   },
   "outputs": [],
   "source": [
    "abalone_features = abalone_train.copy()\n",
    "abalone_labels = abalone_features.pop('Age')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "seK9n71-UBfT"
   },
   "source": [
    "对于此数据集，将以相同的方式处理所有特征。将这些特征打包成单个 NumPy 数组："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:15.749264Z",
     "iopub.status.busy": "2023-11-07T23:47:15.748982Z",
     "iopub.status.idle": "2023-11-07T23:47:15.754757Z",
     "shell.execute_reply": "2023-11-07T23:47:15.754067Z"
    },
    "id": "Dp3N5McbUMwb"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.435, 0.335, 0.11 , ..., 0.136, 0.077, 0.097],\n",
       "       [0.585, 0.45 , 0.125, ..., 0.354, 0.207, 0.225],\n",
       "       [0.655, 0.51 , 0.16 , ..., 0.396, 0.282, 0.37 ],\n",
       "       ...,\n",
       "       [0.53 , 0.42 , 0.13 , ..., 0.374, 0.167, 0.249],\n",
       "       [0.395, 0.315, 0.105, ..., 0.118, 0.091, 0.119],\n",
       "       [0.45 , 0.355, 0.12 , ..., 0.115, 0.067, 0.16 ]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "abalone_features = np.array(abalone_features)\n",
    "abalone_features"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "1C1yFOxLOdxh"
   },
   "source": [
    "接下来，制作一个回归模型来预测年龄。由于只有一个输入张量，这里使用 `tf.keras.Sequential` 模型就足够了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:15.758924Z",
     "iopub.status.busy": "2023-11-07T23:47:15.758208Z",
     "iopub.status.idle": "2023-11-07T23:47:18.086950Z",
     "shell.execute_reply": "2023-11-07T23:47:18.085876Z"
    },
    "id": "d8zzNrZqOmfB"
   },
   "outputs": [],
   "source": [
    "abalone_model = tf.keras.Sequential([\n",
    "  layers.Dense(64),\n",
    "  layers.Dense(1)\n",
    "])\n",
    "\n",
    "abalone_model.compile(loss = tf.keras.losses.MeanSquaredError(),\n",
    "                      optimizer = tf.keras.optimizers.Adam())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "j6IWeP78O2wE"
   },
   "source": [
    "要训练该模型，请将特征和标签传递给 `Model.fit`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:18.091625Z",
     "iopub.status.busy": "2023-11-07T23:47:18.090868Z",
     "iopub.status.idle": "2023-11-07T23:47:22.027212Z",
     "shell.execute_reply": "2023-11-07T23:47:22.026485Z"
    },
    "id": "uZdpCD92SN3Z"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
      "I0000 00:00:1699400839.261974  571141 device_compiler.h:186] Compiled cluster using XLA!  This line is logged at most once for the lifetime of the process.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 2:21 - loss: 101.9437"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 22/104 [=====>........................] - ETA: 0s - loss: 95.2627   "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 44/104 [===========>..................] - ETA: 0s - loss: 89.1451"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 65/104 [=================>............] - ETA: 0s - loss: 80.6143"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 86/104 [=======================>......] - ETA: 0s - loss: 71.3353"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 2s 2ms/step - loss: 64.6157\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 2/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 29.5109"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 22/104 [=====>........................] - ETA: 0s - loss: 18.4533"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 42/104 [===========>..................] - ETA: 0s - loss: 15.2012"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 63/104 [=================>............] - ETA: 0s - loss: 13.3386"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 85/104 [=======================>......] - ETA: 0s - loss: 12.3196"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 11.5237\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 3/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 10.9910"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 24/104 [=====>........................] - ETA: 0s - loss: 8.3957 "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 47/104 [============>.................] - ETA: 0s - loss: 8.0881"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 70/104 [===================>..........] - ETA: 0s - loss: 8.3030"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 92/104 [=========================>....] - ETA: 0s - loss: 8.1226"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 8.1954\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 4/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 6.1413"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 24/104 [=====>........................] - ETA: 0s - loss: 8.2923"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 47/104 [============>.................] - ETA: 0s - loss: 8.5084"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 69/104 [==================>...........] - ETA: 0s - loss: 8.1870"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 92/104 [=========================>....] - ETA: 0s - loss: 7.6837"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 7.7570\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 5/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 10.4424"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 8.0771 "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 45/104 [===========>..................] - ETA: 0s - loss: 7.8526"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 68/104 [==================>...........] - ETA: 0s - loss: 7.6984"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 90/104 [========================>.....] - ETA: 0s - loss: 7.5845"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 7.3885\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 6/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 7.1712"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 7.1029"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 45/104 [===========>..................] - ETA: 0s - loss: 6.5226"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 66/104 [==================>...........] - ETA: 0s - loss: 6.7688"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 88/104 [========================>.....] - ETA: 0s - loss: 7.0163"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 7.0926\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 7/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 5.6098"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 6.0588"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 46/104 [============>.................] - ETA: 0s - loss: 6.4743"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 68/104 [==================>...........] - ETA: 0s - loss: 6.5212"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 91/104 [=========================>....] - ETA: 0s - loss: 6.8465"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 6.8470\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 8/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 5.5962"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 7.2752"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 46/104 [============>.................] - ETA: 0s - loss: 6.8060"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 68/104 [==================>...........] - ETA: 0s - loss: 6.8497"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 90/104 [========================>.....] - ETA: 0s - loss: 6.7589"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 6.7037\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 9/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 4.3912"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 24/104 [=====>........................] - ETA: 0s - loss: 6.6435"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 47/104 [============>.................] - ETA: 0s - loss: 6.6816"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 70/104 [===================>..........] - ETA: 0s - loss: 6.3140"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 92/104 [=========================>....] - ETA: 0s - loss: 6.5410"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 6.5731\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 10/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 5.8961"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 22/104 [=====>........................] - ETA: 0s - loss: 6.1178"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 44/104 [===========>..................] - ETA: 0s - loss: 6.2430"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 66/104 [==================>...........] - ETA: 0s - loss: 6.1084"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 88/104 [========================>.....] - ETA: 0s - loss: 6.3872"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 6.4726\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.src.callbacks.History at 0x7fba9c17c910>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "abalone_model.fit(abalone_features, abalone_labels, epochs=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "GapLOj1OOTQH"
   },
   "source": [
    "您刚刚看到了使用 CSV 数据训练模型的最基本方式。接下来，您将学习如何应用预处理来归一化数值列。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "B87Rd1SOUv02"
   },
   "source": [
    "## 基本预处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "yCrB2Jd-U0Vt"
   },
   "source": [
    "对模型的输入进行归一化是一种很好的做法。Keras 预处理层提供了一种便捷方式来将此归一化构建到您的模型。\n",
    "\n",
    "`tf.keras.layers.Normalization` 层会预先计算每列的均值和方差，并使用这些内容对数据进行归一化。\n",
    "\n",
    "首先，创建层："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:22.031010Z",
     "iopub.status.busy": "2023-11-07T23:47:22.030725Z",
     "iopub.status.idle": "2023-11-07T23:47:22.036180Z",
     "shell.execute_reply": "2023-11-07T23:47:22.035416Z"
    },
    "id": "H2WQpDU5VRk7"
   },
   "outputs": [],
   "source": [
    "normalize = layers.Normalization()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "hGgEZE-7Vpt6"
   },
   "source": [
    "然后，使用 `Normalization.adapt()` 方法使归一化层适应您的数据。\n",
    "\n",
    "注：仅将您的训练数据用于 `PreprocessingLayer.adapt` 方法。不要使用您的验证数据或测试数据。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:22.039905Z",
     "iopub.status.busy": "2023-11-07T23:47:22.039207Z",
     "iopub.status.idle": "2023-11-07T23:47:22.421960Z",
     "shell.execute_reply": "2023-11-07T23:47:22.421141Z"
    },
    "id": "2WgOPIiOVpLg"
   },
   "outputs": [],
   "source": [
    "normalize.adapt(abalone_features)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rE6vh0byV7cE"
   },
   "source": [
    "然后，将归一化层用于您的模型："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:22.426294Z",
     "iopub.status.busy": "2023-11-07T23:47:22.426017Z",
     "iopub.status.idle": "2023-11-07T23:47:26.119049Z",
     "shell.execute_reply": "2023-11-07T23:47:26.118251Z"
    },
    "id": "quPcZ9dTWA9A"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 1:52 - loss: 122.1690"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 22/104 [=====>........................] - ETA: 0s - loss: 104.8419  "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 43/104 [===========>..................] - ETA: 0s - loss: 102.0931"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 64/104 [=================>............] - ETA: 0s - loss: 98.3096 "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 86/104 [=======================>......] - ETA: 0s - loss: 94.3227"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 1s 2ms/step - loss: 92.2746\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 2/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 69.8699"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 70.6138"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 44/104 [===========>..................] - ETA: 0s - loss: 67.1762"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 64/104 [=================>............] - ETA: 0s - loss: 61.9383"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 83/104 [======================>.......] - ETA: 0s - loss: 57.5425"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - ETA: 0s - loss: 53.1503"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 3ms/step - loss: 53.1503\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 3/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 27.6175"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 22/104 [=====>........................] - ETA: 0s - loss: 27.3872"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 43/104 [===========>..................] - ETA: 0s - loss: 24.2987"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 65/104 [=================>............] - ETA: 0s - loss: 20.5882"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 87/104 [========================>.....] - ETA: 0s - loss: 18.1379"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 16.5479\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 4/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 7.6246"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 8.1219"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 45/104 [===========>..................] - ETA: 0s - loss: 7.1057"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 67/104 [==================>...........] - ETA: 0s - loss: 6.4601"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 89/104 [========================>.....] - ETA: 0s - loss: 6.0833"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 5.9912\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 5/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 1.5492"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 4.5862"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 45/104 [===========>..................] - ETA: 0s - loss: 4.5351"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 67/104 [==================>...........] - ETA: 0s - loss: 4.9657"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 89/104 [========================>.....] - ETA: 0s - loss: 5.1963"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 5.1468\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 6/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 5.9418"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 4.8608"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 46/104 [============>.................] - ETA: 0s - loss: 4.9782"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 68/104 [==================>...........] - ETA: 0s - loss: 4.8786"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 90/104 [========================>.....] - ETA: 0s - loss: 4.9959"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 5.0204\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 7/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 5.5926"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 5.3847"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 45/104 [===========>..................] - ETA: 0s - loss: 5.2681"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 66/104 [==================>...........] - ETA: 0s - loss: 5.1667"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 88/104 [========================>.....] - ETA: 0s - loss: 5.0252"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 4.9907\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 8/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 3.9144"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 24/104 [=====>........................] - ETA: 0s - loss: 5.1471"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 47/104 [============>.................] - ETA: 0s - loss: 5.2076"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 70/104 [===================>..........] - ETA: 0s - loss: 5.1551"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 93/104 [=========================>....] - ETA: 0s - loss: 5.1030"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 4.9757\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 9/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 3.4640"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 24/104 [=====>........................] - ETA: 0s - loss: 4.5150"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 47/104 [============>.................] - ETA: 0s - loss: 4.8335"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 69/104 [==================>...........] - ETA: 0s - loss: 4.9005"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 92/104 [=========================>....] - ETA: 0s - loss: 4.9880"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 4.9543\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 10/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "  1/104 [..............................] - ETA: 0s - loss: 5.8363"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 23/104 [=====>........................] - ETA: 0s - loss: 5.1082"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 44/104 [===========>..................] - ETA: 0s - loss: 4.9832"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 66/104 [==================>...........] - ETA: 0s - loss: 4.7715"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      " 88/104 [========================>.....] - ETA: 0s - loss: 4.7601"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "104/104 [==============================] - 0s 2ms/step - loss: 4.9403\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.src.callbacks.History at 0x7fba6c040610>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "norm_abalone_model = tf.keras.Sequential([\n",
    "  normalize,\n",
    "  layers.Dense(64),\n",
    "  layers.Dense(1)\n",
    "])\n",
    "\n",
    "norm_abalone_model.compile(loss = tf.keras.losses.MeanSquaredError(),\n",
    "                           optimizer = tf.keras.optimizers.Adam())\n",
    "\n",
    "norm_abalone_model.fit(abalone_features, abalone_labels, epochs=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Wuqj601Qw0Ml"
   },
   "source": [
    "## 混合数据类型\n",
    "\n",
    "The \"Titanic\" dataset contains information about the passengers on the Titanic. The nominal task on this dataset is to predict who survived.\n",
    "\n",
    "![The Titanic](images/csv/Titanic.jpg)\n",
    "\n",
    "Image [from Wikimedia](https://commons.wikimedia.org/wiki/File:RMS_Titanic_3.jpg)\n",
    "\n",
    "The raw data can easily be loaded as a Pandas `DataFrame`, but is not immediately usable as input to a TensorFlow model.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.122776Z",
     "iopub.status.busy": "2023-11-07T23:47:26.122502Z",
     "iopub.status.idle": "2023-11-07T23:47:26.194388Z",
     "shell.execute_reply": "2023-11-07T23:47:26.193676Z"
    },
    "id": "GS-dBMpuYMnz"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>survived</th>\n",
       "      <th>sex</th>\n",
       "      <th>age</th>\n",
       "      <th>n_siblings_spouses</th>\n",
       "      <th>parch</th>\n",
       "      <th>fare</th>\n",
       "      <th>class</th>\n",
       "      <th>deck</th>\n",
       "      <th>embark_town</th>\n",
       "      <th>alone</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>male</td>\n",
       "      <td>22.0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>7.2500</td>\n",
       "      <td>Third</td>\n",
       "      <td>unknown</td>\n",
       "      <td>Southampton</td>\n",
       "      <td>n</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>female</td>\n",
       "      <td>38.0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>71.2833</td>\n",
       "      <td>First</td>\n",
       "      <td>C</td>\n",
       "      <td>Cherbourg</td>\n",
       "      <td>n</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>female</td>\n",
       "      <td>26.0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>7.9250</td>\n",
       "      <td>Third</td>\n",
       "      <td>unknown</td>\n",
       "      <td>Southampton</td>\n",
       "      <td>y</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>female</td>\n",
       "      <td>35.0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>53.1000</td>\n",
       "      <td>First</td>\n",
       "      <td>C</td>\n",
       "      <td>Southampton</td>\n",
       "      <td>n</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>male</td>\n",
       "      <td>28.0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>8.4583</td>\n",
       "      <td>Third</td>\n",
       "      <td>unknown</td>\n",
       "      <td>Queenstown</td>\n",
       "      <td>y</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   survived     sex   age  n_siblings_spouses  parch     fare  class     deck  \\\n",
       "0         0    male  22.0                   1      0   7.2500  Third  unknown   \n",
       "1         1  female  38.0                   1      0  71.2833  First        C   \n",
       "2         1  female  26.0                   0      0   7.9250  Third  unknown   \n",
       "3         1  female  35.0                   1      0  53.1000  First        C   \n",
       "4         0    male  28.0                   0      0   8.4583  Third  unknown   \n",
       "\n",
       "   embark_town alone  \n",
       "0  Southampton     n  \n",
       "1    Cherbourg     n  \n",
       "2  Southampton     y  \n",
       "3  Southampton     n  \n",
       "4   Queenstown     y  "
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "titanic = pd.read_csv(\"https://storage.googleapis.com/tf-datasets/titanic/train.csv\")\n",
    "titanic.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.197707Z",
     "iopub.status.busy": "2023-11-07T23:47:26.197439Z",
     "iopub.status.idle": "2023-11-07T23:47:26.201631Z",
     "shell.execute_reply": "2023-11-07T23:47:26.200958Z"
    },
    "id": "D8rCGIK1ZzKx"
   },
   "outputs": [],
   "source": [
    "titanic_features = titanic.copy()\n",
    "titanic_labels = titanic_features.pop('survived')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "urHOwpCDYtcI"
   },
   "source": [
    "由于数据类型和范围不同，您不能简单地将特征堆叠到 NumPy 数组中并将其传递给 `tf.keras.Sequential` 模型。每列都需要单独处理。\n",
    "\n",
    "作为一种选择，您可以（使用您喜欢的任何工具）离线预处理数据，将分类列转换为数值列，然后将处理后的输出传递给 TensorFlow 模型。这种方式的缺点是，如果保存并导出模型，预处理不会随之保存。Keras 预处理层能够避免这个问题，因为它们是模型的一部分。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Bta4Sx0Zau5v"
   },
   "source": [
    "在此示例中，您将构建一个使用 [Keras 函数式 API](https://tensorflow.google.cn/guide/keras/functional) 实现预处理逻辑的模型。您也可以通过[子类化](https://tensorflow.google.cn/guide/keras/custom_layers_and_models)来实现。\n",
    "\n",
    "函数式 API 会对“符号”张量进行运算。正常的 \"eager\" 张量有一个值。相比之下，这些“符号”张量则没有值。相反，它们会跟踪在它们上面运行的运算，并构建可以稍后运行的计算的表示。以下是一个简单示例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.204829Z",
     "iopub.status.busy": "2023-11-07T23:47:26.204579Z",
     "iopub.status.idle": "2023-11-07T23:47:26.220657Z",
     "shell.execute_reply": "2023-11-07T23:47:26.219964Z"
    },
    "id": "730F16_97D-3"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<KerasTensor: shape=(None,) dtype=float32 (created by layer 'tf.__operators__.add')>"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create a symbolic input\n",
    "input = tf.keras.Input(shape=(), dtype=tf.float32)\n",
    "\n",
    "# Perform a calculation using the input\n",
    "result = 2*input + 1\n",
    "\n",
    "# the result doesn't have a value\n",
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.224282Z",
     "iopub.status.busy": "2023-11-07T23:47:26.223613Z",
     "iopub.status.idle": "2023-11-07T23:47:26.230109Z",
     "shell.execute_reply": "2023-11-07T23:47:26.229451Z"
    },
    "id": "RtcNXWB18kMJ"
   },
   "outputs": [],
   "source": [
    "calc = tf.keras.Model(inputs=input, outputs=result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.233104Z",
     "iopub.status.busy": "2023-11-07T23:47:26.232855Z",
     "iopub.status.idle": "2023-11-07T23:47:26.241318Z",
     "shell.execute_reply": "2023-11-07T23:47:26.240650Z"
    },
    "id": "fUGQOUqZ8sa-"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.0\n",
      "5.0\n"
     ]
    }
   ],
   "source": [
    "print(calc(1).numpy())\n",
    "print(calc(2).numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rNS9lT7f6_U2"
   },
   "source": [
    "要构建预处理模型，首先要构建一组符号 `tf.keras.Input` 对象，匹配 CSV 列的名称和数据类型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.244510Z",
     "iopub.status.busy": "2023-11-07T23:47:26.244251Z",
     "iopub.status.idle": "2023-11-07T23:47:26.260126Z",
     "shell.execute_reply": "2023-11-07T23:47:26.259433Z"
    },
    "id": "5WODe_1da3yw"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'sex': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'sex')>,\n",
       " 'age': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'age')>,\n",
       " 'n_siblings_spouses': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'n_siblings_spouses')>,\n",
       " 'parch': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'parch')>,\n",
       " 'fare': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'fare')>,\n",
       " 'class': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'class')>,\n",
       " 'deck': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'deck')>,\n",
       " 'embark_town': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'embark_town')>,\n",
       " 'alone': <KerasTensor: shape=(None, 1) dtype=string (created by layer 'alone')>}"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "inputs = {}\n",
    "\n",
    "for name, column in titanic_features.items():\n",
    "  dtype = column.dtype\n",
    "  if dtype == object:\n",
    "    dtype = tf.string\n",
    "  else:\n",
    "    dtype = tf.float32\n",
    "\n",
    "  inputs[name] = tf.keras.Input(shape=(1,), name=name, dtype=dtype)\n",
    "\n",
    "inputs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "aaheJFmymq8l"
   },
   "source": [
    "预处理逻辑的第一步是将数值输入串联在一起，并通过归一化层运行它们："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.263245Z",
     "iopub.status.busy": "2023-11-07T23:47:26.262988Z",
     "iopub.status.idle": "2023-11-07T23:47:26.542419Z",
     "shell.execute_reply": "2023-11-07T23:47:26.541668Z"
    },
    "id": "wPRC_E6rkp8D"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<KerasTensor: shape=(None, 4) dtype=float32 (created by layer 'normalization_1')>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numeric_inputs = {name:input for name,input in inputs.items()\n",
    "                  if input.dtype==tf.float32}\n",
    "\n",
    "x = layers.Concatenate()(list(numeric_inputs.values()))\n",
    "norm = layers.Normalization()\n",
    "norm.adapt(np.array(titanic[numeric_inputs.keys()]))\n",
    "all_numeric_inputs = norm(x)\n",
    "\n",
    "all_numeric_inputs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-JoR45Uj712l"
   },
   "source": [
    "收集所有符号预处理结果，稍后将它们串联起来："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.546479Z",
     "iopub.status.busy": "2023-11-07T23:47:26.545766Z",
     "iopub.status.idle": "2023-11-07T23:47:26.549480Z",
     "shell.execute_reply": "2023-11-07T23:47:26.548793Z"
    },
    "id": "M7jIJw5XntdN"
   },
   "outputs": [],
   "source": [
    "preprocessed_inputs = [all_numeric_inputs]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "r0Hryylyosfm"
   },
   "source": [
    "对于字符串输入，请使用 `tf.keras.layers.StringLookup` 函数将字符串映射到词汇表中的整数索引。接下来，使用 `tf.keras.layers.CategoryEncoding` 将索引转换为适合模型的 `float32` 数据。\n",
    "\n",
    "`tf.keras.layers.CategoryEncoding` 层的默认设置会为每个输入创建一个独热向量。也可以使用 `tf.keras.layers.Embedding`。请参阅[使用预处理层](https://tensorflow.google.cn/guide/keras/preprocessing_layers)指南和[使用 Keras 预处理层对结构化数据进行分类](../structured_data/preprocessing_layers.ipynb)教程，了解有关此主题的更多信息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.552979Z",
     "iopub.status.busy": "2023-11-07T23:47:26.552470Z",
     "iopub.status.idle": "2023-11-07T23:47:26.686094Z",
     "shell.execute_reply": "2023-11-07T23:47:26.685245Z"
    },
    "id": "79fi1Cgan2YV"
   },
   "outputs": [],
   "source": [
    "for name, input in inputs.items():\n",
    "  if input.dtype == tf.float32:\n",
    "    continue\n",
    "  \n",
    "  lookup = layers.StringLookup(vocabulary=np.unique(titanic_features[name]))\n",
    "  one_hot = layers.CategoryEncoding(num_tokens=lookup.vocabulary_size())\n",
    "\n",
    "  x = lookup(input)\n",
    "  x = one_hot(x)\n",
    "  preprocessed_inputs.append(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Wnhv0T7itnc7"
   },
   "source": [
    "您可以使用 `inputs` 和 `processed_inputs` 的集合将所有预处理的输入串联在一起，并构建处理预处理的模型："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.690729Z",
     "iopub.status.busy": "2023-11-07T23:47:26.690042Z",
     "iopub.status.idle": "2023-11-07T23:47:26.913294Z",
     "shell.execute_reply": "2023-11-07T23:47:26.912362Z"
    },
    "id": "XJRzUTe8ukXc"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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HDly8+bNFRUVcsciJ/MfZhf/VaLt+MsGAAAAwHbYWdXM/H4Wabeurm7fvn15eXmfffbZ5s2bDx48KAhCWlra1q1bS0tLT506lZ+ff+zYsdzc3MWLFwuCkJ6evnr1aqkFd3d3o9Ho5uYm7aalpa1evTo0NFR63EytVlt9iC2wZMmSPXv27N+//8aNG8HBwWFhYVVVVS0aXVfIUoe6c+fOmTNn4uLi+vTpM378+F27dv3yyy9yByUD8x9mF/9Vou34ywYAAADAdthT1axRBoMhNjbWw8Nj/PjxgYGBFy5cMH1UU1OTlJTk6en58MMPx8XF7dix49atWy1tf9euXV5ez2dH5wAAIABJREFUXt9//327Rt1WWq1206ZNb7/99vDhwz09PdetW6fX69PS0lrRVCfOknXcuXOnpqbmm2++mTt3bq9evSZOnJiZmVlTUyN3XHLqmr9KtB1/2QAAAADYFCe5A2grJyenfv36Sdsqlcr830U+Pj7u7u7SdnBwcG1t7ZUrV0aMGNGi9o2/aq+A20VhYaHBYAgJCZF2XV1d1Wq19ChTS9lmlpKSktqrqY5z9+5d893bt28LgvDVV1/94x//MBqNgwYNGj58eH19vYOD3demW6pr/irRdp3+LxsAAAAA+2L3VTNHR0fTtiiK5h/V19ebthv8s8d812AwWGg/IiIiIiKirVG2t0b/FWcafvNHJ9hqlrRabTu21kH4t3RTuuavEm3X6f+yAQAAALAvdl81s6CkpKSystLDw0MQhIKCAoVCIS1V0717d9PbD2/evKnX602XNPgXvs0KCgpycnK6ePGitKy1Tqe7evXq888/L7R8dLaZpcTExI7uou0++eQT893u3bvX1NSMGTMmJibm6aeffueddwRB6II3mllmm/MNNqLT/2UDAAAAYF868z/p3dzcli9fXlFRkZ+fn5ycPHv27B49egiCMGzYsKKioiNHjlRWViYnJyuVStMl3t7excXF1dXVUVFRqampgq2ua6NSqWJiYtauXZufn6/VapcuXapUKqOjo4UWjk7o1Fmyjm7duimVyt/+9rebN28uLy//8ssvZ8yYYZ4umGO+wQL+sgEAAACwLUaraJeO4uPjTWFfunRp48aNpl2tVhsQECBtv/LKK0ajcevWrf3798/MzOzfv7+rq+uLL754+/ZtU1MLFizw8PAYMGBATk6O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wOkPfFX9Cc1hRXMw0uDz+Z999plAIFi1alUzX9JUhw4d3n///R9++CE/P/+33347dOjQ9u3baZ6vzULQ5JklJQCtUVWUt57xG22h6VmGpnHSN7Omx4LSs1uLgiHXNvMgog+y6XJVH6Wa/47N7z/b3js5OzsbGRnRTIumi6X39PTcu3dvo4XNL3eLukRtlhvY4/Lly6NHj46NjU1ISBCJREOGDGE6IgAAfabxEQo3NzdDQ8Om8ze3SGlpKTVnc35+vqGhobOzc35+fk1NTUhIiLm5OUEQ9NdNkHr06OHr67tz5847d+4kJibSPLPRwJObmxuXy6UmdpVIJAUFBdTXgARB+Pn5HT169Pz582PGjBk7dqyRkdG3337bv39/tY+OtcLz58+p27dT2SMIolOnTi9evCCXFxcXS6VS6iXNDNvV1ZWmCoaGhh9//PHOnTt37twZGBhILlRLewCdw+FwPvjggxMnThQUFNTV1ZG/HFHj0eHi4mJgYJCfn08+LCsro9p8c6g6wOkPfKX9Cc1hRag+GJVydHRUHOLh8XivX79u/k4p8vX1VTzofHx8evXqVVJSQj5kthCurq40eWa2BKB9jSpOoTnXND1fKz3L0DTOt57iG1F6dlO1Oy095anKgKogG+2XWCyuqKho/tsRrTps1dg7kffl+Pe///3mzRvF5YGBgWRudbT0zaS03DRRMVJuYJX79+9PmzbN399/xowZt27dCggIYDoiAAD9p/FRMz6fHxERsXr16kuXLkml0qtXr/bt2zc7O7tFGzE0NIyOjhaLxbm5ucnJyXPmzDE3N3dxceHxeBs3bnz16tXDhw937drVzK316NFj69at8fHx165dU/Uca2vrkpKS6urqkJCQjRs38vn88PDwNWvW5ObmisXi6OhoHo8XFhZGPX/y5Mm//fZb165deTyekZHR+PHj161bx5JbQJqZmS1btqyyslIxewRBDBo06P79+xcvXqyqqkpOTubxeNRLGu0+zcbpqxAUFPTgwYONGzdSJ3W1tAfQLTk5OSNHjnzy5EldXV1paWltba2rqyvRkmb2VtbW1p988kliYmJ+fn5FRcXy5cvNzMya/3JVB/hbD3yiSX9Cc1gRqg9GpSorKyMjI8kU7d2798iRI23pUiIjI2/duiWVSsvKypKTkwsLC8ePH0+uYrwQNHlmtgSgfVTFb968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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "preprocessed_inputs_cat = layers.Concatenate()(preprocessed_inputs)\n",
    "\n",
    "titanic_preprocessing = tf.keras.Model(inputs, preprocessed_inputs_cat)\n",
    "\n",
    "tf.keras.utils.plot_model(model = titanic_preprocessing , rankdir=\"LR\", dpi=72, show_shapes=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "PNHxrNW8vdda"
   },
   "source": [
    "此 `model` 仅包含输入预处理。您可以运行它以查看其对您的数据进行了哪些操作。Keras 模型不会自动转换 Pandas <code>DataFrames</code>，因为不清楚是应该将其转换为一个张量还是张量字典。因此，将其转换为张量字典："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.917898Z",
     "iopub.status.busy": "2023-11-07T23:47:26.917590Z",
     "iopub.status.idle": "2023-11-07T23:47:26.922779Z",
     "shell.execute_reply": "2023-11-07T23:47:26.921855Z"
    },
    "id": "5YjdYyMEacwQ"
   },
   "outputs": [],
   "source": [
    "titanic_features_dict = {name: np.array(value) \n",
    "                         for name, value in titanic_features.items()}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "0nKJYoPByada"
   },
   "source": [
    "切出第一个训练样本并将其传递给此预处理模型，您会看到数字特征和字符串独热全部串联在一起："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:26.926556Z",
     "iopub.status.busy": "2023-11-07T23:47:26.925996Z",
     "iopub.status.idle": "2023-11-07T23:47:28.035502Z",
     "shell.execute_reply": "2023-11-07T23:47:28.034729Z"
    },
    "id": "SjnmU8PSv8T3"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(1, 28), dtype=float32, numpy=\n",
       "array([[-0.61 ,  0.395, -0.479, -0.497,  0.   ,  0.   ,  1.   ,  0.   ,\n",
       "         0.   ,  0.   ,  1.   ,  0.   ,  0.   ,  0.   ,  0.   ,  0.   ,\n",
       "         0.   ,  0.   ,  0.   ,  1.   ,  0.   ,  0.   ,  0.   ,  1.   ,\n",
       "         0.   ,  0.   ,  1.   ,  0.   ]], dtype=float32)>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}\n",
    "titanic_preprocessing(features_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "qkBf4LvmzMDp"
   },
   "source": [
    "接下来，在此基础上构建模型："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:28.039012Z",
     "iopub.status.busy": "2023-11-07T23:47:28.038735Z",
     "iopub.status.idle": "2023-11-07T23:47:28.188278Z",
     "shell.execute_reply": "2023-11-07T23:47:28.187418Z"
    },
    "id": "coIPtGaCzUV7"
   },
   "outputs": [],
   "source": [
    "def titanic_model(preprocessing_head, inputs):\n",
    "  body = tf.keras.Sequential([\n",
    "    layers.Dense(64),\n",
    "    layers.Dense(1)\n",
    "  ])\n",
    "\n",
    "  preprocessed_inputs = preprocessing_head(inputs)\n",
    "  result = body(preprocessed_inputs)\n",
    "  model = tf.keras.Model(inputs, result)\n",
    "\n",
    "  model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n",
    "                optimizer=tf.keras.optimizers.Adam())\n",
    "  return model\n",
    "\n",
    "titanic_model = titanic_model(titanic_preprocessing, inputs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "LK5uBQQF2KbZ"
   },
   "source": [
    "训练模型时，将特征字典作为 `x` 传递，将标签作为 `y` 传递。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:28.192436Z",
     "iopub.status.busy": "2023-11-07T23:47:28.192152Z",
     "iopub.status.idle": "2023-11-07T23:47:30.741126Z",
     "shell.execute_reply": "2023-11-07T23:47:30.740359Z"
    },
    "id": "D1gVfwJ61ejz"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 30s - loss: 0.6159"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "13/20 [==================>...........] - ETA: 0s - loss: 0.5816 "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 2s 4ms/step - loss: 0.5669\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 2/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.4976"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.5234"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.5039\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 3/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.5891"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "15/20 [=====================>........] - ETA: 0s - loss: 0.4731"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4748\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 4/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.4022"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4678"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4562\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 5/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.3903"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4497"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4436\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 6/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.3655"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4231"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4357\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 7/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.3896"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4154"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4293\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 8/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.4782"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4362"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4253\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 9/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.4934"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4070"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4244\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 10/10\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.3007"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4141"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4222\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.src.callbacks.History at 0x7fbbe14a9070>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "titanic_model.fit(x=titanic_features_dict, y=titanic_labels, epochs=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "LxgJarZk3bfH"
   },
   "source": [
    "由于预处理是模型的一部分，您可以保存模型并将其重新加载到其他地方并获得相同的结果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:30.744806Z",
     "iopub.status.busy": "2023-11-07T23:47:30.744520Z",
     "iopub.status.idle": "2023-11-07T23:47:33.378169Z",
     "shell.execute_reply": "2023-11-07T23:47:33.377099Z"
    },
    "id": "Ay-8ymNA2ZCh"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Assets written to: test/assets\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Assets written to: test/assets\n"
     ]
    }
   ],
   "source": [
    "titanic_model.save('test')\n",
    "reloaded = tf.keras.models.load_model('test')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:33.383554Z",
     "iopub.status.busy": "2023-11-07T23:47:33.382910Z",
     "iopub.status.idle": "2023-11-07T23:47:33.446479Z",
     "shell.execute_reply": "2023-11-07T23:47:33.445704Z"
    },
    "id": "Qm6jMTpD20lK"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tf.Tensor([[-1.899]], shape=(1, 1), dtype=float32)\n",
      "tf.Tensor([[-1.899]], shape=(1, 1), dtype=float32)\n"
     ]
    }
   ],
   "source": [
    "features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}\n",
    "\n",
    "before = titanic_model(features_dict)\n",
    "after = reloaded(features_dict)\n",
    "assert (before-after)<1e-3\n",
    "print(before)\n",
    "print(after)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7VsPlxIRZpXf"
   },
   "source": [
    "## 使用 tf.data\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "NyVDCwGzR5HW"
   },
   "source": [
    "在前一部分中，您在训练模型时依赖了模型的内置数据乱序和批处理。\n",
    "\n",
    "如果您需要对输入数据流水线进行更多控制或需要使用不易放入内存的数据：请使用 `tf.data`。\n",
    "\n",
    "有关更多示例，请参阅 [`tf.data`：构建 TensorFlow 输入流水线](../../guide/data.ipynb)指南。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "gP5Y1jM2Sor0"
   },
   "source": [
    "### 有关内存数据\n",
    "\n",
    "作为将 `tf.data` 应用于 CSV 数据的第一个样本，请考虑使用以下代码手动切分上一个部分中的特征字典。对于每个索引，它会为每个特征获取该索引：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:33.451057Z",
     "iopub.status.busy": "2023-11-07T23:47:33.450223Z",
     "iopub.status.idle": "2023-11-07T23:47:33.455011Z",
     "shell.execute_reply": "2023-11-07T23:47:33.454309Z"
    },
    "id": "i8wE-MVuVu7_"
   },
   "outputs": [],
   "source": [
    "import itertools\n",
    "\n",
    "def slices(features):\n",
    "  for i in itertools.count():\n",
    "    # For each feature take index `i`\n",
    "    example = {name:values[i] for name, values in features.items()}\n",
    "    yield example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "cQ3RTbS9YEal"
   },
   "source": [
    "运行此代码并打印第一个样本："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:33.458856Z",
     "iopub.status.busy": "2023-11-07T23:47:33.458239Z",
     "iopub.status.idle": "2023-11-07T23:47:33.462671Z",
     "shell.execute_reply": "2023-11-07T23:47:33.461997Z"
    },
    "id": "Wwq8XK88WwFk"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sex                : male\n",
      "age                : 22.0\n",
      "n_siblings_spouses : 1\n",
      "parch              : 0\n",
      "fare               : 7.25\n",
      "class              : Third\n",
      "deck               : unknown\n",
      "embark_town        : Southampton\n",
      "alone              : n\n"
     ]
    }
   ],
   "source": [
    "for example in slices(titanic_features_dict):\n",
    "  for name, value in example.items():\n",
    "    print(f\"{name:19s}: {value}\")\n",
    "  break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vvp8Dct6YOIE"
   },
   "source": [
    "内存数据加载程序中最基本的 `tf.data.Dataset` 是 `Dataset.from_tensor_slices` 构造函数。这会返回一个 `tf.data.Dataset`，它将在 TensorFlow 中实现上述 `slices` 函数的泛化版本。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:33.466443Z",
     "iopub.status.busy": "2023-11-07T23:47:33.465787Z",
     "iopub.status.idle": "2023-11-07T23:47:33.474260Z",
     "shell.execute_reply": "2023-11-07T23:47:33.473556Z"
    },
    "id": "2gEJthslYxeV"
   },
   "outputs": [],
   "source": [
    "features_ds = tf.data.Dataset.from_tensor_slices(titanic_features_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-ZC0rTpMZMZK"
   },
   "source": [
    "您可以像任何其他 Python 可迭代对象一样迭代 `tf.data.Dataset`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:33.478347Z",
     "iopub.status.busy": "2023-11-07T23:47:33.477679Z",
     "iopub.status.idle": "2023-11-07T23:47:33.492288Z",
     "shell.execute_reply": "2023-11-07T23:47:33.491504Z"
    },
    "id": "gOHbiefaY4ag"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sex                : b'male'\n",
      "age                : 22.0\n",
      "n_siblings_spouses : 1\n",
      "parch              : 0\n",
      "fare               : 7.25\n",
      "class              : b'Third'\n",
      "deck               : b'unknown'\n",
      "embark_town        : b'Southampton'\n",
      "alone              : b'n'\n"
     ]
    }
   ],
   "source": [
    "for example in features_ds:\n",
    "  for name, value in example.items():\n",
    "    print(f\"{name:19s}: {value}\")\n",
    "  break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "uwcFoVJWZY5F"
   },
   "source": [
    "`from_tensor_slices` 函数可以处理嵌套字典或元组的任何结构。以下代码创建了一个 `(features_dict, labels)` 对的数据集："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:33.496289Z",
     "iopub.status.busy": "2023-11-07T23:47:33.495524Z",
     "iopub.status.idle": "2023-11-07T23:47:33.506626Z",
     "shell.execute_reply": "2023-11-07T23:47:33.505927Z"
    },
    "id": "xIHGBy76Zcrx"
   },
   "outputs": [],
   "source": [
    "titanic_ds = tf.data.Dataset.from_tensor_slices((titanic_features_dict, titanic_labels))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "gQwxitt8c2GK"
   },
   "source": [
    "要使用此 `Dataset` 训练模型，您至少需要对数据进行 `shuffle` 和 `batch`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:33.510919Z",
     "iopub.status.busy": "2023-11-07T23:47:33.510235Z",
     "iopub.status.idle": "2023-11-07T23:47:33.521210Z",
     "shell.execute_reply": "2023-11-07T23:47:33.520540Z"
    },
    "id": "SbJcbldhddeC"
   },
   "outputs": [],
   "source": [
    "titanic_batches = titanic_ds.shuffle(len(titanic_labels)).batch(32)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-4FRqhRFuoJx"
   },
   "source": [
    "不是将 `features` 和 `labels` 传递给 `Model.fit`，而是传递数据集："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:33.524736Z",
     "iopub.status.busy": "2023-11-07T23:47:33.524451Z",
     "iopub.status.idle": "2023-11-07T23:47:34.393746Z",
     "shell.execute_reply": "2023-11-07T23:47:34.393007Z"
    },
    "id": "8yXkNPumdBtB"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 7s - loss: 0.2701"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4223"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4209\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 2/5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.2889"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "15/20 [=====================>........] - ETA: 0s - loss: 0.4129"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4204\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 3/5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.4769"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "15/20 [=====================>........] - ETA: 0s - loss: 0.4060"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4205\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 4/5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.5053"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4209"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4205\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 5/5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 1/20 [>.............................] - ETA: 0s - loss: 0.5134"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "14/20 [====================>.........] - ETA: 0s - loss: 0.4280"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "20/20 [==============================] - 0s 4ms/step - loss: 0.4193\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.src.callbacks.History at 0x7fbbe1495790>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "titanic_model.fit(titanic_batches, epochs=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "qXuibiv9exT7"
   },
   "source": [
    "### 从单个文件\n",
    "\n",
    "到目前为止，本教程已经使用了内存数据。`tf.data` 是用于构建数据流水线的高度可扩展的工具包，并提供了一些用于处理加载 CSV 文件的函数。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:34.397649Z",
     "iopub.status.busy": "2023-11-07T23:47:34.396990Z",
     "iopub.status.idle": "2023-11-07T23:47:34.445928Z",
     "shell.execute_reply": "2023-11-07T23:47:34.445172Z"
    },
    "id": "Ncf5t6tgL5ZI"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading data from https://storage.googleapis.com/tf-datasets/titanic/train.csv\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      " 8192/30874 [======>.......................] - ETA: 0s"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n",
      "30874/30874 [==============================] - 0s 0us/step\n"
     ]
    }
   ],
   "source": [
    "titanic_file_path = tf.keras.utils.get_file(\"train.csv\", \"https://storage.googleapis.com/tf-datasets/titanic/train.csv\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "t4N-plO4tDXd"
   },
   "source": [
    "现在，从文件中读取 CSV 数据并创建一个 `tf.data.Dataset`。\n",
    "\n",
    "（有关完整文档，请参阅 `tf.data.experimental.make_csv_dataset`）\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:34.449555Z",
     "iopub.status.busy": "2023-11-07T23:47:34.449286Z",
     "iopub.status.idle": "2023-11-07T23:47:34.514055Z",
     "shell.execute_reply": "2023-11-07T23:47:34.513306Z"
    },
    "id": "yIbUscB9sqha"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/data/experimental/ops/readers.py:573: ignore_errors (from tensorflow.python.data.experimental.ops.error_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use `tf.data.Dataset.ignore_errors` instead.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/data/experimental/ops/readers.py:573: ignore_errors (from tensorflow.python.data.experimental.ops.error_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use `tf.data.Dataset.ignore_errors` instead.\n"
     ]
    }
   ],
   "source": [
    "titanic_csv_ds = tf.data.experimental.make_csv_dataset(\n",
    "    titanic_file_path,\n",
    "    batch_size=5, # Artificially small to make examples easier to show.\n",
    "    label_name='survived',\n",
    "    num_epochs=1,\n",
    "    ignore_errors=True,)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Sf3v3BKgy4AG"
   },
   "source": [
    "此函数包括许多方便的功能，因此很容易处理数据。这包括:\n",
    "\n",
    "- 使用列标题作为字典键。\n",
    "- 自动确定每列的类型。\n",
    "\n",
    "小心：请确保在 `tf.data.experimental.make_csv_dataset` 中设置 `num_epochs` 参数，否则 `tf.data.Dataset` 的默认行为是无限循环。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:34.517891Z",
     "iopub.status.busy": "2023-11-07T23:47:34.517604Z",
     "iopub.status.idle": "2023-11-07T23:47:34.584520Z",
     "shell.execute_reply": "2023-11-07T23:47:34.583676Z"
    },
    "id": "v4oMO9MIxgTG"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sex                 : [b'female' b'female' b'male' b'male' b'male']\n",
      "age                 : [50. 31. 28. 28. 28.]\n",
      "n_siblings_spouses  : [0 0 1 0 0]\n",
      "parch               : [0 0 2 0 0]\n",
      "fare                : [28.712  7.854 23.45  56.496  7.896]\n",
      "class               : [b'First' b'Third' b'Third' b'Third' b'Third']\n",
      "deck                : [b'C' b'unknown' b'unknown' b'unknown' b'unknown']\n",
      "embark_town         : [b'Cherbourg' b'Southampton' b'Southampton' b'Southampton' b'Southampton']\n",
      "alone               : [b'y' b'y' b'n' b'y' b'y']\n",
      "\n",
      "label               : [0 0 0 0 0]\n"
     ]
    }
   ],
   "source": [
    "for batch, label in titanic_csv_ds.take(1):\n",
    "  for key, value in batch.items():\n",
    "    print(f\"{key:20s}: {value}\")\n",
    "  print()\n",
    "  print(f\"{'label':20s}: {label}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "k-TgA6o2Ja6U"
   },
   "source": [
    "注：如果您运行两次上述代码单元，它将产生不同的结果。`tf.data.experimental.make_csv_dataset` 的默认设置包括 `shuffle_buffer_size=1000`，这对于这个小型数据集来说已经绰绰有余，但可能不适用于实际的数据集。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "d6uviU_KCCWD"
   },
   "source": [
    "它还可以对数据进行即时解压。下面是一个用 gzip 压缩的 CSV 文件，其中包含 [Metro Interstate Traffic Dataset](https://archive.ics.uci.edu/ml/datasets/Metro+Interstate+Traffic+Volume)。\n",
    "\n",
    "![交通堵塞。](images/csv/traffic.jpg)\n",
    "\n",
    "图片[来自 Wikimedia](https://commons.wikimedia.org/wiki/File:Trafficjam.jpg)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:34.588534Z",
     "iopub.status.busy": "2023-11-07T23:47:34.588236Z",
     "iopub.status.idle": "2023-11-07T23:47:35.121197Z",
     "shell.execute_reply": "2023-11-07T23:47:35.120348Z"
    },
    "id": "kT7oZI2E46Q8"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading data from https://archive.ics.uci.edu/ml/machine-learning-databases/00492/Metro_Interstate_Traffic_Volume.csv.gz\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "   8192/Unknown - 0s 0us/step"
     ]
    }
   ],
   "source": [
    "traffic_volume_csv_gz = tf.keras.utils.get_file(\n",
    "    'Metro_Interstate_Traffic_Volume.csv.gz', \n",
    "    \"https://archive.ics.uci.edu/ml/machine-learning-databases/00492/Metro_Interstate_Traffic_Volume.csv.gz\",\n",
    "    cache_dir='.', cache_subdir='traffic')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "F-IOsFHbCw0i"
   },
   "source": [
    "将 `compression_type` 参数设置为直接从压缩文件中读取："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:35.125225Z",
     "iopub.status.busy": "2023-11-07T23:47:35.124948Z",
     "iopub.status.idle": "2023-11-07T23:47:35.389707Z",
     "shell.execute_reply": "2023-11-07T23:47:35.388889Z"
    },
    "id": "ar0MPEVJ5NeA"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "holiday             : [b'None' b'None' b'None' b'None' b'None']\n",
      "temp                : [256.34 296.9  268.41 289.85 266.65]\n",
      "rain_1h             : [0. 0. 0. 0. 0.]\n",
      "snow_1h             : [0. 0. 0. 0. 0.]\n",
      "clouds_all          : [90 80  1  0 90]\n",
      "weather_main        : [b'Clouds' b'Mist' b'Clear' b'Clear' b'Clouds']\n",
      "weather_description : [b'overcast clouds' b'mist' b'sky is clear' b'Sky is Clear'\n",
      " b'overcast clouds']\n",
      "date_time           : [b'2013-01-14 07:00:00' b'2013-08-30 08:00:00' b'2013-02-09 17:00:00'\n",
      " b'2013-09-12 09:00:00' b'2012-12-17 19:00:00']\n",
      "\n",
      "label               : [6579 6042 4374 5687 2953]\n"
     ]
    }
   ],
   "source": [
    "traffic_volume_csv_gz_ds = tf.data.experimental.make_csv_dataset(\n",
    "    traffic_volume_csv_gz,\n",
    "    batch_size=256,\n",
    "    label_name='traffic_volume',\n",
    "    num_epochs=1,\n",
    "    compression_type=\"GZIP\")\n",
    "\n",
    "for batch, label in traffic_volume_csv_gz_ds.take(1):\n",
    "  for key, value in batch.items():\n",
    "    print(f\"{key:20s}: {value[:5]}\")\n",
    "  print()\n",
    "  print(f\"{'label':20s}: {label[:5]}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "p12Y6tGq8D6M"
   },
   "source": [
    "注：如果需要在 `tf.data` 流水线中解析这些日期时间字符串，您可以使用 `tfa.text.parse_time`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "EtrAXzYGP3l0"
   },
   "source": [
    "### 缓存"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "fN2dL_LRP83r"
   },
   "source": [
    "解析 CSV 数据有一些开销。对于小型模型，这可能是训练的瓶颈。\n",
    "\n",
    "根据您的用例，使用 `Dataset.cache` 或 `tf.data.Dataset.snapshot` 可能是个好主意，这样 CSV 数据仅会在第一个周期进行解析。\n",
    "\n",
    "`cache` 和 `snapshot` 方法的主要区别在于 `cache` 文件只能由创建它们的 TensorFlow 进程使用，而 `snapshot` 文件可以被其他进程读取。\n",
    "\n",
    "例如，在没有缓存的情况下迭代 `traffic_volume_csv_gz_ds` 20 次可能需要大约 15 秒，而使用缓存大约需要 2 秒。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:35.393800Z",
     "iopub.status.busy": "2023-11-07T23:47:35.393521Z",
     "iopub.status.idle": "2023-11-07T23:47:46.711854Z",
     "shell.execute_reply": "2023-11-07T23:47:46.711001Z"
    },
    "id": "Qk38Sw4MO4eh"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".\n",
      "CPU times: user 15 s, sys: 2.52 s, total: 17.5 s\n",
      "Wall time: 11.3 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "for i, (batch, label) in enumerate(traffic_volume_csv_gz_ds.repeat(20)):\n",
    "  if i % 40 == 0:\n",
    "    print('.', end='')\n",
    "print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "pN3HtDONh5TX"
   },
   "source": [
    "注：`Dataset.cache` 会存储第一个周期的数据并按顺序回放。因此，使用 `cache` 方法会禁用流水线中较早的任何乱序内容。下面，在 `Dataset.cache` 之后重新添加了 `Dataset.shuffle`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:46.715367Z",
     "iopub.status.busy": "2023-11-07T23:47:46.715074Z",
     "iopub.status.idle": "2023-11-07T23:47:48.589272Z",
     "shell.execute_reply": "2023-11-07T23:47:48.588498Z"
    },
    "id": "r5Jj72MrPbnh"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..............\n",
      "CPU times: user 1.9 s, sys: 285 ms, total: 2.19 s\n",
      "Wall time: 1.87 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "caching = traffic_volume_csv_gz_ds.cache().shuffle(1000)\n",
    "\n",
    "for i, (batch, label) in enumerate(caching.shuffle(1000).repeat(20)):\n",
    "  if i % 40 == 0:\n",
    "    print('.', end='')\n",
    "print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "wN7uUBjmgNZ9"
   },
   "source": [
    "注：`tf.data.Dataset.snapshot` 文件用于在使用时*临时*存储数据集。这*不是*长期存储的格式。文件格式被视为内部详细信息，无法在 TensorFlow 各版本之间保证。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:48.592913Z",
     "iopub.status.busy": "2023-11-07T23:47:48.592618Z",
     "iopub.status.idle": "2023-11-07T23:47:50.715544Z",
     "shell.execute_reply": "2023-11-07T23:47:50.714777Z"
    },
    "id": "PHGD1E8ktUvW"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "............."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "............."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".....\n",
      "CPU times: user 2.68 s, sys: 738 ms, total: 3.42 s\n",
      "Wall time: 2.12 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "snapshotting = traffic_volume_csv_gz_ds.snapshot('titanic.tfsnap').shuffle(1000)\n",
    "\n",
    "for i, (batch, label) in enumerate(snapshotting.shuffle(1000).repeat(20)):\n",
    "  if i % 40 == 0:\n",
    "    print('.', end='')\n",
    "print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "fUSSegnMCGRz"
   },
   "source": [
    "如果加载 CSV 文件减慢了数据加载速度，并且 `Dataset.cache` 和 `tf.data.Dataset.snapshot` 不足以满足您的用例，请考虑将数据重新编码为更简化的格式。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "M0iGXv9pC5kr"
   },
   "source": [
    "### 多个文件"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9FFzHQrCDH4w"
   },
   "source": [
    "到目前为止，本部分中的所有示例都可以在没有 `tf.data` 的情况下轻松完成。处理文件集合时，`tf.data` 可以真正简化事情。\n",
    "\n",
    "例如，将 [Character Font Images](https://archive.ics.uci.edu/ml/datasets/Character+Font+Images) 数据集作为 CSV 文件的集合分发，每种字体一个集合。\n",
    "\n",
    "![字体](images/csv/fonts.jpg)\n",
    "\n",
    "图像作者：<a href=\"https://pixabay.com/users/wilhei-883152/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=705667\">Willi Heidelbach</a>，来源：<a href=\"https://pixabay.com/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=705667\">Pixabay</a>\n",
    "\n",
    "下载数据集，并查看里面的文件："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:50.719800Z",
     "iopub.status.busy": "2023-11-07T23:47:50.719157Z",
     "iopub.status.idle": "2023-11-07T23:47:58.746732Z",
     "shell.execute_reply": "2023-11-07T23:47:58.745897Z"
    },
    "id": "RmVknMdJh5ks"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading data from https://archive.ics.uci.edu/ml/machine-learning-databases/00417/fonts.zip\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "   8192/Unknown - 0s 0us/step"
     ]
    }
   ],
   "source": [
    "fonts_zip = tf.keras.utils.get_file(\n",
    "    'fonts.zip',  \"https://archive.ics.uci.edu/ml/machine-learning-databases/00417/fonts.zip\",\n",
    "    cache_dir='.', cache_subdir='fonts',\n",
    "    extract=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:58.751395Z",
     "iopub.status.busy": "2023-11-07T23:47:58.750649Z",
     "iopub.status.idle": "2023-11-07T23:47:58.757791Z",
     "shell.execute_reply": "2023-11-07T23:47:58.757107Z"
    },
    "id": "xsDlMCnyi55e"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['fonts/AGENCY.csv',\n",
       " 'fonts/ARIAL.csv',\n",
       " 'fonts/BAITI.csv',\n",
       " 'fonts/BANKGOTHIC.csv',\n",
       " 'fonts/BASKERVILLE.csv',\n",
       " 'fonts/BAUHAUS.csv',\n",
       " 'fonts/BELL.csv',\n",
       " 'fonts/BERLIN.csv',\n",
       " 'fonts/BERNARD.csv',\n",
       " 'fonts/BITSTREAMVERA.csv']"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pathlib\n",
    "font_csvs =  sorted(str(p) for p in pathlib.Path('fonts').glob(\"*.csv\"))\n",
    "\n",
    "font_csvs[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:58.761096Z",
     "iopub.status.busy": "2023-11-07T23:47:58.760619Z",
     "iopub.status.idle": "2023-11-07T23:47:58.765317Z",
     "shell.execute_reply": "2023-11-07T23:47:58.764651Z"
    },
    "id": "lRAEJx9ROAGl"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "153"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(font_csvs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "19Udrw9iG-FS"
   },
   "source": [
    "在处理一堆文件时，可以将 glob 样式的 `file_pattern` 传递给 `tf.data.experimental.make_csv_dataset` 函数。每次迭代都会打乱文件的顺序。\n",
    "\n",
    "使用 `num_parallel_reads` 参数对并行读取多少文件并交错在一起进行设置。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:58.768599Z",
     "iopub.status.busy": "2023-11-07T23:47:58.768050Z",
     "iopub.status.idle": "2023-11-07T23:47:59.645990Z",
     "shell.execute_reply": "2023-11-07T23:47:59.644966Z"
    },
    "id": "6TSUNdT6iG58"
   },
   "outputs": [],
   "source": [
    "fonts_ds = tf.data.experimental.make_csv_dataset(\n",
    "    file_pattern = \"fonts/*.csv\",\n",
    "    batch_size=10, num_epochs=1,\n",
    "    num_parallel_reads=20,\n",
    "    shuffle_buffer_size=10000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "XMoexinLHYFa"
   },
   "source": [
    "这些 CSV 文件会将图像展平成一行。列名的格式为 `r{row}c{column}`。下面是第一个批次："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:47:59.650772Z",
     "iopub.status.busy": "2023-11-07T23:47:59.650047Z",
     "iopub.status.idle": "2023-11-07T23:48:01.769941Z",
     "shell.execute_reply": "2023-11-07T23:48:01.769003Z"
    },
    "id": "RmFvBWxxi3pq"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "font                : [b'BASKERVILLE' b'RAGE' b'COMPLEX' b'MISTRAL' b'COUNTRYBLUEPRINT'\n",
      " b'SWIS721' b'RICHARD' b'STYLUS' b'SWIS721' b'SWIS721']\n",
      "fontVariant         : [b'BASKERVILLE OLD FACE' b'RAGE ITALIC' b'COMPLEX' b'MISTRAL'\n",
      " b'COUNTRYBLUEPRINT' b'SWIS721 LTEX BT' b'POOR RICHARD' b'STYLUS BT'\n",
      " b'SWIS721 LTEX BT' b'SWIS721 LTEX BT']\n",
      "m_label             : [  68  111 9578  383 8225  126   92   93  376  382]\n",
      "strength            : [0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4]\n",
      "italic              : [1 0 0 0 0 0 0 0 1 0]\n",
      "orientation         : [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n",
      "m_top               : [34 55 28 29 38 60 29 38 23 34]\n",
      "m_left              : [22 20 25 25 24 26 21 20 37 22]\n",
      "originalH           : [45 21 74 49 54  9 60 54 61 50]\n",
      "originalW           : [55 21 38 14 25 44 39 12 47 33]\n",
      "h                   : [20 20 20 20 20 20 20 20 20 20]\n",
      "w                   : [20 20 20 20 20 20 20 20 20 20]\n",
      "r0c0                : [  1   1   1   1 255   1 168 161   1   1]\n",
      "r0c1                : [  1   1   1   1 255   1 255 161   1   1]\n",
      "r0c2                : [  1   1   1   7 255   1  57 161   1   1]\n",
      "r0c3                : [  1   1   1  47 255   1   1 161   1 137]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "...\n",
      "[total: 412 features]\n"
     ]
    }
   ],
   "source": [
    "for features in fonts_ds.take(1):\n",
    "  for i, (name, value) in enumerate(features.items()):\n",
    "    if i>15:\n",
    "      break\n",
    "    print(f\"{name:20s}: {value}\")\n",
    "print('...')\n",
    "print(f\"[total: {len(features)} features]\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "xrC3sKdeOhb5"
   },
   "source": [
    "#### 可选：打包字段\n",
    "\n",
    "您可能不想像这样在单独的列中处理每个像素。在尝试使用此数据集之前，请务必将像素打包到图像张量中。\n",
    "\n",
    "下面是解析列名，从而为每个示例构建图像的代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:01.774004Z",
     "iopub.status.busy": "2023-11-07T23:48:01.773428Z",
     "iopub.status.idle": "2023-11-07T23:48:01.779214Z",
     "shell.execute_reply": "2023-11-07T23:48:01.778565Z"
    },
    "id": "hct5EMEWNyfH"
   },
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "def make_images(features):\n",
    "  image = [None]*400\n",
    "  new_feats = {}\n",
    "\n",
    "  for name, value in features.items():\n",
    "    match = re.match('r(\\d+)c(\\d+)', name)\n",
    "    if match:\n",
    "      image[int(match.group(1))*20+int(match.group(2))] = value\n",
    "    else:\n",
    "      new_feats[name] = value\n",
    "\n",
    "  image = tf.stack(image, axis=0)\n",
    "  image = tf.reshape(image, [20, 20, -1])\n",
    "  new_feats['image'] = image\n",
    "\n",
    "  return new_feats"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "61qy8utAwARP"
   },
   "source": [
    "将该函数应用于数据集中的每个批次："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:01.782924Z",
     "iopub.status.busy": "2023-11-07T23:48:01.782291Z",
     "iopub.status.idle": "2023-11-07T23:48:04.414751Z",
     "shell.execute_reply": "2023-11-07T23:48:04.413941Z"
    },
    "id": "DJnnfIW9baE4"
   },
   "outputs": [],
   "source": [
    "fonts_image_ds = fonts_ds.map(make_images)\n",
    "\n",
    "for features in fonts_image_ds.take(1):\n",
    "  break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "_ThqrthGwHSm"
   },
   "source": [
    "绘制生成的图像："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:04.419327Z",
     "iopub.status.busy": "2023-11-07T23:48:04.418772Z",
     "iopub.status.idle": "2023-11-07T23:48:05.242178Z",
     "shell.execute_reply": "2023-11-07T23:48:05.241404Z"
    },
    "id": "I5dcey31T_tk"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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m222WRxxxBGx66671nu8lZrFjEDdXXnllXHSSSfFH/7wh9h7773rPQ50uFqtFl//+tfjvPPOi+bm5ve95oADDogxY8ZE7969O3i6MvgnM6CupkyZEqeffnqce+65yhDF+o//+I8499xzo3v37vHNb34zJk6cGIsWLYqZM2fGNddcEwMHDoxbbrkl9t5771i8eHG9x10peULUwa6++uo4/vjj45577vH4E4B46KGHYrvttovu3bvHPffcEyNHjnzPNbNnz44ddtghJk6cGN/+9rfj7LPPrsOkKzdPiIAO9dxzz0VDQ0OMGjXqn16z2WabRdeuXWPGjBkdOBnUx+jRoyMi4qyzznrfMhQR0a9fv7j00ksjIuLiiy8OzzLankIEdKjhw4fHqFGjYuzYsTFhwoT35Pfff3+MGzcuDjzwwBgwYEAdJoSOddddd0VExDHHHJNet/vuu0f//v1j1qxZMW7cuI4YrSgKEdDhTjnllIiIuOKKK96T/f1lJ554YofOBPWwcOHCmD17dnTt2jWGDh1aef3w4cMjIuLll19u79GKoxABHe6ggw6KAQMGxNVXXx2LFi169+Vz586NG264IYYMGRJ77LFHHSeEjvH//9NXS0tL5fV/v6ZTJ1++25q/0XY0aNCgaGho+If/HX/88RERMWrUqPdkxx13XH0Hhg7SpUuX+NSnPhVz5syJX/3qV+++fMyYMfHOO+/Epz/96WhoaKjjhNAxevToEauvvnosWbIkXnrppcrrp0yZEhER6667bnuPVhw/ZdaORo8eHXPnzv2Hlz3xxBPx29/+No499tgYNGjQP2RbbrllHHTQQR02H9TT9OnTY+DAgbHDDjvEn//854j4n2+mnjBhQrz88svRr1+/Ok8IHeOjH/1o3HjjjfHDH/4wPvOZz/zT655++unYfPPNo3///jF9+nRPidqYQtTB/Ng9/D+HHHJI3HzzzTF+/Ph4/fXXY4cddogjjjgirr/++nqPBh3m7rvvjt133z0aGxvj6aefjm7dur3vdccee2xce+218dWvfjXOPffcDp5y5adeAnXz92+uvvzyy30zNcXabbfd4rjjjosJEybESSed9L7XjBkzJq699tpobGy0g6id+F1mQN38/b+Kr7nmmli4cGFstNFG6X4iWFlddtllMX369Ljqqqti8eLFcckll0Tv3r2jVqvFhRde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",
      "text/plain": [
       "<Figure size 720x720 with 9 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from matplotlib import pyplot as plt\n",
    "\n",
    "plt.figure(figsize=(6,6), dpi=120)\n",
    "\n",
    "for n in range(9):\n",
    "  plt.subplot(3,3,n+1)\n",
    "  plt.imshow(features['image'][..., n])\n",
    "  plt.title(chr(features['m_label'][n]))\n",
    "  plt.axis('off')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7-nNR0Nncdd1"
   },
   "source": [
    "## 低级函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "3jiGZeUijJNd"
   },
   "source": [
    "到目前为止，本教程重点介绍了用于读取 CSV 数据的最高级别实用程序。如果您的用例不符合基本模式，还有其他两个 API 可能对高级用户有所帮助。\n",
    "\n",
    "- `tf.io.decode_csv`：用于将文本行解析为 CSV 列张量列表的函数。\n",
    "- `tf.data.experimental.CsvDataset`：较低级别的 CSV 数据集构造函数。\n",
    "\n",
    "本部分会重新创建 `tf.data.experimental.make_csv_dataset` 提供的功能，以演示如何使用此较低级别的功能。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "LL_ixywomOHW"
   },
   "source": [
    "### `tf.io.decode_csv`\n",
    "\n",
    "此函数会将字符串或字符串列表解码为列列表。\n",
    "\n",
    "与 `tf.data.experimental.make_csv_dataset` 不同，此函数不会尝试猜测列数据类型。您可以通过为每列提供包含正确类型值的记录 `record_defaults` 值列表来指定列类型。\n",
    "\n",
    "要使用 <code>tf.io.decode_csv</code> 将 Titanic 数据<strong>作为字符串</strong>读取，您可以使用以下代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.246494Z",
     "iopub.status.busy": "2023-11-07T23:48:05.246013Z",
     "iopub.status.idle": "2023-11-07T23:48:05.252473Z",
     "shell.execute_reply": "2023-11-07T23:48:05.251757Z"
    },
    "id": "m1D2C-qdlqeW"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['', '', '', '', '', '', '', '', '', '']"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text = pathlib.Path(titanic_file_path).read_text()\n",
    "lines = text.split('\\n')[1:-1]\n",
    "\n",
    "all_strings = [str()]*10\n",
    "all_strings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.255897Z",
     "iopub.status.busy": "2023-11-07T23:48:05.255292Z",
     "iopub.status.idle": "2023-11-07T23:48:05.263425Z",
     "shell.execute_reply": "2023-11-07T23:48:05.262745Z"
    },
    "id": "9W4UeJYyHPx5"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n"
     ]
    }
   ],
   "source": [
    "features = tf.io.decode_csv(lines, record_defaults=all_strings) \n",
    "\n",
    "for f in features:\n",
    "  print(f\"type: {f.dtype.name}, shape: {f.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "j8TaHSQFoQL4"
   },
   "source": [
    "要使用它们的实际类型解析它们，请创建相应类型的 `record_defaults` 列表： "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.267016Z",
     "iopub.status.busy": "2023-11-07T23:48:05.266553Z",
     "iopub.status.idle": "2023-11-07T23:48:05.270431Z",
     "shell.execute_reply": "2023-11-07T23:48:05.269794Z"
    },
    "id": "rzUjR59yoUe1"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0,male,22.0,1,0,7.25,Third,unknown,Southampton,n\n"
     ]
    }
   ],
   "source": [
    "print(lines[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.273780Z",
     "iopub.status.busy": "2023-11-07T23:48:05.273262Z",
     "iopub.status.idle": "2023-11-07T23:48:05.278362Z",
     "shell.execute_reply": "2023-11-07T23:48:05.277706Z"
    },
    "id": "7sPTunxwoeWU"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, '', 0.0, 0, 0, 0.0, '', '', '', '']"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "titanic_types = [int(), str(), float(), int(), int(), float(), str(), str(), str(), str()]\n",
    "titanic_types"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.281628Z",
     "iopub.status.busy": "2023-11-07T23:48:05.281066Z",
     "iopub.status.idle": "2023-11-07T23:48:05.289059Z",
     "shell.execute_reply": "2023-11-07T23:48:05.288430Z"
    },
    "id": "n3NlViCzoB7F"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "type: int32, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: float32, shape: (627,)\n",
      "type: int32, shape: (627,)\n",
      "type: int32, shape: (627,)\n",
      "type: float32, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n",
      "type: string, shape: (627,)\n"
     ]
    }
   ],
   "source": [
    "features = tf.io.decode_csv(lines, record_defaults=titanic_types) \n",
    "\n",
    "for f in features:\n",
    "  print(f\"type: {f.dtype.name}, shape: {f.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "m-LkTUTnpn2P"
   },
   "source": [
    "注：在大批量行上调用 `tf.io.decode_csv` 比在单个 CSV 文本行上调用更有效。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Yp1UItJmqGqw"
   },
   "source": [
    "### `tf.data.experimental.CsvDataset`\n",
    "\n",
    "`tf.data.experimental.CsvDataset` 类提供了一个最小的 CSV `Dataset` 接口，没有 `tf.data.experimental.make_csv_dataset` 函数的便利功能：列标题解析、列类型推断、自动乱序、文件交错。\n",
    "\n",
    "此构造函数使用 `record_defaults` 的方式与 `tf.io.decode_csv` 相同：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.292639Z",
     "iopub.status.busy": "2023-11-07T23:48:05.292130Z",
     "iopub.status.idle": "2023-11-07T23:48:05.310279Z",
     "shell.execute_reply": "2023-11-07T23:48:05.309620Z"
    },
    "id": "9OzZLp3krP-t"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, b'male', 22.0, 1, 0, 7.25, b'Third', b'unknown', b'Southampton', b'n']\n"
     ]
    }
   ],
   "source": [
    "simple_titanic = tf.data.experimental.CsvDataset(titanic_file_path, record_defaults=titanic_types, header=True)\n",
    "\n",
    "for example in simple_titanic.take(1):\n",
    "  print([e.numpy() for e in example])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "_HBmfI-Ks7dw"
   },
   "source": [
    "上面的代码基本等价于："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.313807Z",
     "iopub.status.busy": "2023-11-07T23:48:05.313185Z",
     "iopub.status.idle": "2023-11-07T23:48:05.404242Z",
     "shell.execute_reply": "2023-11-07T23:48:05.403422Z"
    },
    "id": "E5O5d69Yq7gG"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, b'male', 22.0, 1, 0, 7.25, b'Third', b'unknown', b'Southampton', b'n']\n"
     ]
    }
   ],
   "source": [
    "def decode_titanic_line(line):\n",
    "  return tf.io.decode_csv(line, titanic_types)\n",
    "\n",
    "manual_titanic = (\n",
    "    # Load the lines of text\n",
    "    tf.data.TextLineDataset(titanic_file_path)\n",
    "    # Skip the header row.\n",
    "    .skip(1)\n",
    "    # Decode the line.\n",
    "    .map(decode_titanic_line)\n",
    ")\n",
    "\n",
    "for example in manual_titanic.take(1):\n",
    "  print([e.numpy() for e in example])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5R3ralsnt2AC"
   },
   "source": [
    "#### 多个文件\n",
    "\n",
    "要使用 `tf.data.experimental.CsvDataset` 解析字体数据集，您首先需要确定 `record_defaults` 的列类型。首先检查一个文件的第一行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.408185Z",
     "iopub.status.busy": "2023-11-07T23:48:05.407428Z",
     "iopub.status.idle": "2023-11-07T23:48:05.416359Z",
     "shell.execute_reply": "2023-11-07T23:48:05.415523Z"
    },
    "id": "3tlFOTjCvAI5"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AGENCY,AGENCY FB,64258,0.400000,0,0.000000,35,21,51,22,20,20,1,1,1,21,101,210,255,255,255,255,255,255,255,255,255,255,255,255,255,255,1,1,1,93,255,255,255,176,146,146,146,146,146,146,146,146,216,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,141,141,141,182,255,255,255,172,141,141,141,115,1,1,1,1,163,255,255,255,255,255,255,255,255,255,255,255,255,255,255,209,1,1,1,1,163,255,255,255,6,6,6,96,255,255,255,74,6,6,6,5,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255\n"
     ]
    }
   ],
   "source": [
    "font_line = pathlib.Path(font_csvs[0]).read_text().splitlines()[1]\n",
    "print(font_line)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "etyGu8K_ySRz"
   },
   "source": [
    "只有前两个字段是字符串，其余的都是整数或浮点数，通过计算逗号的个数可以得到特征总数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.419593Z",
     "iopub.status.busy": "2023-11-07T23:48:05.419294Z",
     "iopub.status.idle": "2023-11-07T23:48:05.423358Z",
     "shell.execute_reply": "2023-11-07T23:48:05.422648Z"
    },
    "id": "crgZZn0BzkSB"
   },
   "outputs": [],
   "source": [
    "num_font_features = font_line.count(',')+1\n",
    "font_column_types = [str(), str()] + [float()]*(num_font_features-2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "YeK2Pw540RNj"
   },
   "source": [
    "`tf.data.experimental.CsvDataset` 构造函数可以获取输入文件列表，但会按顺序读取它们。CSV 列表中的第一个文件是 `AGENCY.csv`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.426885Z",
     "iopub.status.busy": "2023-11-07T23:48:05.426305Z",
     "iopub.status.idle": "2023-11-07T23:48:05.431260Z",
     "shell.execute_reply": "2023-11-07T23:48:05.430574Z"
    },
    "id": "_SvL5Uvl0r0N"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'fonts/AGENCY.csv'"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "font_csvs[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "EfAX3G8Xywy6"
   },
   "source": [
    "因此，当您将文件列表传递给 `CsvDataset` 时，会首先读取 `AGENCY.csv` 中的记录："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.434747Z",
     "iopub.status.busy": "2023-11-07T23:48:05.434112Z",
     "iopub.status.idle": "2023-11-07T23:48:05.470038Z",
     "shell.execute_reply": "2023-11-07T23:48:05.469359Z"
    },
    "id": "Gtr1E66VmBqj"
   },
   "outputs": [],
   "source": [
    "simple_font_ds = tf.data.experimental.CsvDataset(\n",
    "    font_csvs, \n",
    "    record_defaults=font_column_types, \n",
    "    header=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.473568Z",
     "iopub.status.busy": "2023-11-07T23:48:05.473059Z",
     "iopub.status.idle": "2023-11-07T23:48:05.549053Z",
     "shell.execute_reply": "2023-11-07T23:48:05.548279Z"
    },
    "id": "k750Mgq4yt_o"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b'AGENCY'\n",
      "b'AGENCY'\n",
      "b'AGENCY'\n",
      "b'AGENCY'\n",
      "b'AGENCY'\n",
      "b'AGENCY'\n",
      "b'AGENCY'\n",
      "b'AGENCY'\n",
      "b'AGENCY'\n",
      "b'AGENCY'\n"
     ]
    }
   ],
   "source": [
    "for row in simple_font_ds.take(10):\n",
    "  print(row[0].numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "NiqWKQV21FrE"
   },
   "source": [
    "要交错多个文件，请使用 `Dataset.interleave`。\n",
    "\n",
    "这是一个包含 CSV 文件名的初始数据集： "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.552726Z",
     "iopub.status.busy": "2023-11-07T23:48:05.552171Z",
     "iopub.status.idle": "2023-11-07T23:48:05.571282Z",
     "shell.execute_reply": "2023-11-07T23:48:05.570550Z"
    },
    "id": "t9dS3SNb23W8"
   },
   "outputs": [],
   "source": [
    "font_files = tf.data.Dataset.list_files(\"fonts/*.csv\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "TNiLHMXpzHy5"
   },
   "source": [
    "这会在每个周期对文件名进行乱序："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.574909Z",
     "iopub.status.busy": "2023-11-07T23:48:05.574373Z",
     "iopub.status.idle": "2023-11-07T23:48:05.617486Z",
     "shell.execute_reply": "2023-11-07T23:48:05.616820Z"
    },
    "id": "zNd-TYyNzIgg"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1:\n",
      "     b'fonts/TEMPUS.csv'\n",
      "     b'fonts/PERPETUA.csv'\n",
      "     b'fonts/KRISTEN.csv'\n",
      "     b'fonts/MISTRAL.csv'\n",
      "     b'fonts/CENTURY.csv'\n",
      "    ...\n",
      "\n",
      "Epoch 2:\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "     b'fonts/OCRB.csv'\n",
      "     b'fonts/ARIAL.csv'\n",
      "     b'fonts/STYLUS.csv'\n",
      "     b'fonts/TIMES.csv'\n",
      "     b'fonts/BOOK.csv'\n",
      "    ...\n"
     ]
    }
   ],
   "source": [
    "print('Epoch 1:')\n",
    "for f in list(font_files)[:5]:\n",
    "  print(\"    \", f.numpy())\n",
    "print('    ...')\n",
    "print()\n",
    "\n",
    "print('Epoch 2:')\n",
    "for f in list(font_files)[:5]:\n",
    "  print(\"    \", f.numpy())\n",
    "print('    ...')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "B0QB1PtU3WAN"
   },
   "source": [
    "`interleave` 方法采用 `map_func`，它会为父 `Dataset`的每个元素创建一个子 `Dataset`。\n",
    "\n",
    "在这里，您要从文件数据集的每个元素创建一个 `tf.data.experimental.CsvDataset`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.621041Z",
     "iopub.status.busy": "2023-11-07T23:48:05.620374Z",
     "iopub.status.idle": "2023-11-07T23:48:05.624344Z",
     "shell.execute_reply": "2023-11-07T23:48:05.623596Z"
    },
    "id": "QWp4rH0Q4uPh"
   },
   "outputs": [],
   "source": [
    "def make_font_csv_ds(path):\n",
    "  return tf.data.experimental.CsvDataset(\n",
    "    path, \n",
    "    record_defaults=font_column_types, \n",
    "    header=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "VxRGdLMB5nRF"
   },
   "source": [
    "交错返回的 `Dataset` 通过循环遍历多个子 `Dataset` 来返回元素。请注意，下面的数据集如何在 `cycle_length=3` 三个字体文件中循环："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.627651Z",
     "iopub.status.busy": "2023-11-07T23:48:05.627057Z",
     "iopub.status.idle": "2023-11-07T23:48:05.845578Z",
     "shell.execute_reply": "2023-11-07T23:48:05.844805Z"
    },
    "id": "OePMNF_x1_Cc"
   },
   "outputs": [],
   "source": [
    "font_rows = font_files.interleave(make_font_csv_ds,\n",
    "                                  cycle_length=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:05.849722Z",
     "iopub.status.busy": "2023-11-07T23:48:05.849100Z",
     "iopub.status.idle": "2023-11-07T23:48:06.007320Z",
     "shell.execute_reply": "2023-11-07T23:48:06.006519Z"
    },
    "id": "UORIGWLy54-E"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmpfs/tmp/ipykernel_570970/998453860.py:5: DeprecationWarning: an integer is required (got type numpy.float32).  Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.\n",
      "  fonts_dict['character'].append(chr(row[2].numpy()))\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>font_name</th>\n",
       "      <th>character</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>YI BAITI</td>\n",
       "      <td>？</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>GUNPLAY</td>\n",
       "      <td>€</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>BAITI</td>\n",
       "      <td>？</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>YI BAITI</td>\n",
       "      <td>；</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>GUNPLAY</td>\n",
       "      <td>›</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>BAITI</td>\n",
       "      <td>！</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>YI BAITI</td>\n",
       "      <td>：</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>GUNPLAY</td>\n",
       "      <td>‹</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>BAITI</td>\n",
       "      <td>﹈</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>YI BAITI</td>\n",
       "      <td>，</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  font_name character\n",
       "0  YI BAITI         ？\n",
       "1   GUNPLAY         €\n",
       "2     BAITI         ？\n",
       "3  YI BAITI         ；\n",
       "4   GUNPLAY         ›\n",
       "5     BAITI         ！\n",
       "6  YI BAITI         ：\n",
       "7   GUNPLAY         ‹\n",
       "8     BAITI         ﹈\n",
       "9  YI BAITI         ，"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fonts_dict = {'font_name':[], 'character':[]}\n",
    "\n",
    "for row in font_rows.take(10):\n",
    "  fonts_dict['font_name'].append(row[0].numpy().decode())\n",
    "  fonts_dict['character'].append(chr(row[2].numpy()))\n",
    "\n",
    "pd.DataFrame(fonts_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "mkKZa_HX8zAm"
   },
   "source": [
    "#### 性能\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8BtGHraUApdJ"
   },
   "source": [
    "早些时候，有人注意到 `tf.io.decode_csv` 在一个批次字符串上运行时效率更高。\n",
    "\n",
    "当使用大批量时，可以利用这一事实来提高 CSV 加载性能（但请先尝试使用[缓存](#caching)）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "d35zWMH7MDL1"
   },
   "source": [
    "使用内置加载器 20，2048 个样本批次大约需要 17 秒。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:06.011447Z",
     "iopub.status.busy": "2023-11-07T23:48:06.011118Z",
     "iopub.status.idle": "2023-11-07T23:48:06.914096Z",
     "shell.execute_reply": "2023-11-07T23:48:06.913252Z"
    },
    "id": "ieUVAPryjpJS"
   },
   "outputs": [],
   "source": [
    "BATCH_SIZE=2048\n",
    "fonts_ds = tf.data.experimental.make_csv_dataset(\n",
    "    file_pattern = \"fonts/*.csv\",\n",
    "    batch_size=BATCH_SIZE, num_epochs=1,\n",
    "    num_parallel_reads=100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:06.918451Z",
     "iopub.status.busy": "2023-11-07T23:48:06.918160Z",
     "iopub.status.idle": "2023-11-07T23:48:30.179708Z",
     "shell.execute_reply": "2023-11-07T23:48:30.178966Z"
    },
    "id": "MUC2KW4LkQIz"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "CPU times: user 50.8 s, sys: 4.58 s, total: 55.4 s\n",
      "Wall time: 23.3 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "for i,batch in enumerate(fonts_ds.take(20)):\n",
    "  print('.',end='')\n",
    "\n",
    "print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5lhnh6rZEDS2"
   },
   "source": [
    "将**批量文本行**传递给 `decode_csv` 运行速度更快，大约需要 5 秒："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:30.183571Z",
     "iopub.status.busy": "2023-11-07T23:48:30.183274Z",
     "iopub.status.idle": "2023-11-07T23:48:30.638344Z",
     "shell.execute_reply": "2023-11-07T23:48:30.637466Z"
    },
    "id": "4XbPZV1okVF9"
   },
   "outputs": [],
   "source": [
    "fonts_files = tf.data.Dataset.list_files(\"fonts/*.csv\")\n",
    "fonts_lines = fonts_files.interleave(\n",
    "    lambda fname:tf.data.TextLineDataset(fname).skip(1), \n",
    "    cycle_length=100).batch(BATCH_SIZE)\n",
    "\n",
    "fonts_fast = fonts_lines.map(lambda x: tf.io.decode_csv(x, record_defaults=font_column_types))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-11-07T23:48:30.642557Z",
     "iopub.status.busy": "2023-11-07T23:48:30.642273Z",
     "iopub.status.idle": "2023-11-07T23:48:31.576293Z",
     "shell.execute_reply": "2023-11-07T23:48:31.575330Z"
    },
    "id": "te9C2km-qO8W"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".............."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "......"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "CPU times: user 4.21 s, sys: 139 ms, total: 4.35 s\n",
      "Wall time: 929 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "for i,batch in enumerate(fonts_fast.take(20)):\n",
    "  print('.',end='')\n",
    "\n",
    "print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "aebC1plsMeOi"
   },
   "source": [
    "有关通过使用大批量提高 CSV 性能的另一个示例，请参阅[过拟合和欠拟合教程](../keras/overfit_and_underfit.ipynb)。\n",
    "\n",
    "这种方式可能有效，但请考虑其他选项，例如 `Dataset.cache` 和 `tf.data.Dataset.snapshot`，或者将您的数据重新编码为更简化的格式。"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "csv.ipynb",
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
